home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d26 / asmtut4.arc / CHAP26.DOC < prev    next >
Text File  |  1990-08-10  |  47KB  |  1,152 lines

  1.  
  2.  
  3.  
  4.                                                                            276
  5.  
  6.                            CHAPTER 26 - SIMPLIFYING THE TEMPLATE
  7.  
  8.  
  9.              By the time you have finished this chapter your assembler files
  10.              will look cleaner. Unfortunately there is some heavy sledding
  11.              before we get there.
  12.  
  13.  
  14.              EXITING A PROGRAM
  15.  
  16.              Till now, we have exited most programs with CTRL-C; otherwise the
  17.              program has done a return. A return to what? It has been
  18.              returning to a section of code that does INT 20h, one of the ways
  19.              of quitting a program when everything is in order. Notice the
  20.              "everything is in order" in the last sentence. What happens if
  21.              you have 2 files open, you are off in some subroutine, and you
  22.              have things so hopelessly confused that you might as well give
  23.              up? Can you call INT 20h? The answer is no for two reasons.
  24.              First, you need CS to point to the PSP (program segment prefix).
  25.              and you don't know where the PSP is. Secondly, you need to close
  26.              files. Now, it is possible to make some code to do this, but why
  27.              bother. We have a special interrupt for this:
  28.  
  29.                  INT 21h function 4Ch
  30.                  AH = 4Ch
  31.                  AL = return code
  32.  
  33.              This will close all files, get you out of the program, and give a
  34.              return code that is usable by the calling program. Here's a small
  35.              program. Use template.asm and call this TEST4CH.ASM.
  36.  
  37.                  ; - - - - - - - - - - - - - - - - - - - - - - - - - 
  38.                  CODESTUFF    SEGMENT   PUBLIC  'CODE' 
  39.               
  40.                     ASSUME cs:CODESTUFF, ds:DATASTUFF 
  41.                     EXTRN   get_unsigned_byte:NEAR 
  42.               
  43.                  main   proc far 
  44.               
  45.                  start: 
  46.                          mov  ax, DATASTUFF    ; load ds 
  47.                          mov  ds,ax 
  48.               
  49.                          call get_unsigned_byte    ; value is in al 
  50.                          mov  ah, 4Ch              ; int 21h, function  4Ch 
  51.                          int  21h 
  52.               
  53.                  main   endp 
  54.                  CODESTUFF    ENDS 
  55.                  ; - - - - - - - - - - - - - - - - - - - - - - - - - - 
  56.  
  57.              We have revised the CODESTUFF segment so there is only one EXTRN
  58.              statement and the beginning code:
  59.  
  60.  
  61.              ______________________
  62.  
  63.              The PC Assembler Tutor - Copyright (C) 1990 Chuck Nelson
  64.  
  65.  
  66.  
  67.  
  68.              Chapter 26 - Simplifying The Template                         277
  69.              _____________________________________
  70.  
  71.                  push ds
  72.                  sub  ax, ax
  73.                  push ax
  74.  
  75.              is gone. Since we will never again do a return to the PSP, there
  76.              is no need for this code anymore. 
  77.  
  78.              The program gets a single byte to use as the exit code and then
  79.              exits using int 21h function 4Ch. Get this assembled and linked.
  80.              It should ask for a number and then exit. But where is that
  81.              number? It is available through the operating system. Make the
  82.              following batch file. It runs TEST4CH.EXE and then looks at the
  83.              error code. Unfortunately ERRORLEVEL is not available as an exact
  84.              number to a batch file, so we are checking to see if the return
  85.              code was above a certain level.
  86.  
  87.                  -----------------  DO4CH.BAT -----------------------
  88.                  test4ch 
  89.                  ECHO OFF 
  90.                  IF ERRORLEVEL   1  ECHO The return code was over 0 
  91.                  IF ERRORLEVEL  51  ECHO The return code was over 50 
  92.                  IF ERRORLEVEL 101  ECHO The return code was over 100 
  93.                  IF ERRORLEVEL 151  ECHO The return code was over 150 
  94.                  IF ERRORLEVEL 201  ECHO The return code was over 200 
  95.                  ECHO ON 
  96.                  ----------------------------------------------------
  97.  
  98.              Here's one run of the batch file:
  99.  
  100.                  >do4ch 
  101.                  >int4ch 
  102.               
  103.                  The PC Assembler Helper   Version 1.01 
  104.                  Copyright (C) 1989  Chuck Nelson   All rights reserved. 
  105.                  Enter a number from 0 to 255  172 
  106.               
  107.                  >ECHO OFF 
  108.                  The return code was over 0 
  109.                  The return code was over 50 
  110.                  The return code was over 100 
  111.                  The return code was over 150 
  112.  
  113.              This is what happens to DO4CH.BAT with a return code of 172.
  114.  
  115.              From now on, always use INT 21h function 4Ch to exit.
  116.  
  117.  
  118.              SEGMENTS
  119.  
  120.              Our major simplification has to do with segment names. Before we
  121.              go on with segment simplification, here are the rules the linker
  122.              uses. If you don't remember them, you should review Chapter 10
  123.              before going on.
  124.  
  125.              During the link process, the linker will combine any segments
  126.              which:
  127.  
  128.  
  129.  
  130.  
  131.  
  132.              The PC Assembler Tutor                                        278
  133.              ______________________
  134.  
  135.                  1) have the same name.
  136.                  2) are declared PUBLIC.
  137.                  3) have the same class name (type).
  138.  
  139.              The linker processes object modules from left to right on the
  140.              command line. The classes will be ordered in the ordering in
  141.              which they were encountered (including the empty class type).
  142.              Within each class, the segments will be ordered in the ordering
  143.              in which they were encountered.
  144.  
  145.              If we have all these rules, how do high-level languages manage to
  146.              combine their data and code correctly? The answer is that they
  147.              use standardized segment definitions. Here are the basic ones for
  148.              our data:
  149.  
  150.                  ;---------------------------------------------------
  151.                  _DATA  SEGMENT WORD PUBLIC 'DATA'
  152.                  _DATA  ENDS
  153.                  ;---------------------------------------------------
  154.                  ;---------------------------------------------------
  155.                  CONST  SEGMENT WORD PUBLIC 'CONST'
  156.                  CONST  ENDS
  157.                  ;---------------------------------------------------
  158.                  ;---------------------------------------------------
  159.                  _BSS  SEGMENT WORD PUBLIC 'BSS'
  160.                  _BSS  ENDS
  161.                  ;---------------------------------------------------
  162.                  ;---------------------------------------------------
  163.                  STACK  SEGMENT PARA STACK 'STACK'
  164.                  STACK  ENDS
  165.                  ;---------------------------------------------------
  166.  
  167.              If all the code will fit in one segment we can use a single
  168.              segment name:
  169.  
  170.                  ;---------------------------------------------------
  171.                  _TEXT  SEGMENT WORD PUBLIC 'CODE'
  172.                  _TEXT  ENDS
  173.                  ;---------------------------------------------------
  174.  
  175.              otherwise we can make independent segments, each with an
  176.              independant name:
  177.  
  178.                  ;---------------------------------------------------
  179.                  name_TEXT  SEGMENT WORD PUBLIC 'CODE'
  180.                  name_TEXT  ENDS
  181.                  ;---------------------------------------------------
  182.  
  183.              where the "name" can be anything, but the "_TEXT" remains
  184.              invariable. Any subroutine calls within the segment can be NEAR,
  185.              while any calls to a different segment should be FAR.
  186.  
  187.              The "WORD" in these definitions says that when the linker
  188.              combines segments into a larger segment, each subsegment must
  189.              start at an even address (a word boundary). This has to do with
  190.              the speed of word fetches from memory that we discussed in the
  191.              last chapter. "WORD" is fine for 16 bit data busses, but for a
  192.  
  193.  
  194.  
  195.  
  196.              Chapter 26 - Simplifying The Template                         279
  197.              _____________________________________
  198.  
  199.              80386 you actually want "DWORD" so things are correctly aligned
  200.              with a 32 bit data bus. "PARA" means paragraph and that means
  201.              aligned with a segment starting address (every 16 bytes).
  202.              Everything will work with "PARA". 
  203.  
  204.              For reasons of convenience, compilers put different types of data
  205.              in different segments. For you, there is no reason to use more
  206.              than one segment, and that is:
  207.  
  208.                  ;--------------------------------
  209.                  _DATA  SEGMENT WORD PUBLIC 'DATA'
  210.                  _DATA  ENDS
  211.                  ;--------------------------------
  212.  
  213.              Compilers use these different segments because they can. If they
  214.              were constrained to use only one segment name, they could do it
  215.              with no problem. What is in these different segments?
  216.  
  217.                  _DATA     standard initialized data
  218.                  CONST     data constants
  219.                  _BSS      uninitialized static data
  220.                  STACK     room for the SS:SP stack
  221.  
  222.              So what do these things mean?
  223.  
  224.              _DATA
  225.  
  226.              The _DATA segment stores all initialized data which exists from
  227.              the time the program starts till the time that the program ends.
  228.  
  229.              In C:
  230.                  static int     x = 5;
  231.  
  232.              In Pascal:
  233.                  const
  234.                       my_salary  : real = 52.77
  235.  
  236.              These variables have a specific value at the start of the
  237.              program, even before the first instruction is executed. This
  238.              value may change during the program. The variable exists during
  239.              the whole program.
  240.  
  241.  
  242.              _BSS
  243.  
  244.              The _BSS segment stores all uninitialized data which exists from
  245.              the time the program starts till the time that the program ends.
  246.  
  247.              In C:
  248.                  static int     x ;
  249.  
  250.              In Pascal, any variable declared outside a procedure but without
  251.              an initial value will be in _BSS. In compiled BASIC, everything
  252.              except dynamic arrays is in the _BSS. These variables have an
  253.              indeterminate value at the start of the program and exist during
  254.              the whole program.
  255.  
  256.  
  257.  
  258.  
  259.  
  260.              The PC Assembler Tutor                                        280
  261.              ______________________
  262.  
  263.  
  264.              CONST
  265.  
  266.              CONST takes all constants which are longer than 2 bytes. If the
  267.              compiler is on its toes, anything one or two bytes long will be
  268.              coded into the machine instructions since this is much faster.
  269.              What is a constant? It is anything that has a value but doesn't
  270.              have a variable name:
  271.  
  272.                  value = 275.29 ;
  273.                  printf ( "Mr. Yellow: 'Read my lips - no new taxis!'\n");
  274.                  result =  value / 27.619 ;
  275.                  file_ptr = fopen ( "stuff.doc", "r+") ;
  276.  
  277.              All the numbers and all the text strings need to be stored
  278.              somewhere. They are stored in the CONST segment and given an
  279.              internal name by the compiler so they can be used at the
  280.              appropriate location. They are not available in other parts of
  281.              the program.{1} These constants are sometimes called literals.
  282.  
  283.  
  284.              STACK
  285.  
  286.              BASIC does not use the stack in the same way as Pascal and C. In
  287.              BASIC it is used only for passing variables between subroutines.
  288.              In C and Pascal, most variables are temporary. They come into
  289.              existance at the beginning of the subroutine and they disappear
  290.              upon leaving the subroutine. When you call the subroutine again,
  291.              the values these variables have are indeterminate. These
  292.              variables all exist on the stack relative to BP, the base
  293.              pointer. This is why you can have recursion in C and Pascal but
  294.              not in BASIC. 
  295.  
  296.              As I said, you don't need to put your different types of data in
  297.              different segments. It can all go into _DATA.
  298.  
  299.  
  300.  
  301.              GROUPS
  302.  
  303.              We now come to the bizarre. You will notice that when the linker
  304.              links all these object modules together, it will have four
  305.              distinct segments with each segment having a distinct class name.
  306.              We will get:
  307.  
  308.                  _DATA     'DATA'
  309.                  CONST     'CONST'
  310.                  _BSS      'BSS'
  311.                  STACK     'STACK'
  312.  
  313.              The problem here is that we want to set DS at the beginning of
  314.              ____________________
  315.  
  316.                 1. There is an exception. Some compilers check to make sure
  317.              that there are no duplicates of the constant. These compilers
  318.              give all duplicates the same address so there is only one copy of
  319.              any one constant such as 0, 1, etc.
  320.  
  321.  
  322.  
  323.  
  324.              Chapter 26 - Simplifying The Template                         281
  325.              _____________________________________
  326.  
  327.              the program so that it will reference all the data. How are we
  328.              going to do this? The warped minds of electrical engineers and
  329.              computer scientists spent hours and hours trying to find the most
  330.              obscure way possible to unify data addressing and they came up
  331.              with GROUPS. 
  332.  
  333.              You can tell the linker that you want data from distinct segments
  334.              to be referenced by the offset from the beginning of the lowest
  335.              segment in memory that belongs to the group. Read this about five
  336.              or ten times to get the hang of it. You tell the linker that a
  337.              bunch of different segments belong to a group. It will find the
  338.              segment which is lowest in memory and then whenever you ask for
  339.              the GROUP offset, the linker will calculate the offset from the
  340.              beginning of this first segment. 
  341.  
  342.              The way you define a group is with a name, the word "GROUP", and
  343.              then a list of those segments in the file which belong to the
  344.              group:
  345.  
  346.                  DGROUP  GROUP _DATA, CONST, _BSS, STACK
  347.  
  348.              Note that it is the segment names, not the class names. DGROUP is
  349.              the standard name for the data group. If the assembler gives the
  350.              linker the correct information, the linker will adjust all
  351.              offsets relative to the beginning of the group. The only limit on
  352.              a group is that the distance from the first byte of the group to
  353.              the last byte of the group must be 65535 bytes or less. This is
  354.              because all the group segments must reside in one physical
  355.              segment in memory. 
  356.  
  357.              It is not even necessary for all the segments in a block of
  358.              memory to belong to the group. Consider the following ordering of
  359.              segments in memory.
  360.  
  361.                       _DATA
  362.                       DATASTUFF
  363.                       CONST
  364.                       CODESTUFF
  365.                       _BSS
  366.                       EVENMORESTUFF
  367.                       STACK
  368.  
  369.              As long as the distance from one end of _DATA to the other end of
  370.              STACK is 65535 bytes or less, the linker will adjust the offsets
  371.              in _DATA, CONST, _BSS and STACK relative to the start of DGROUP
  372.              and the linker will adjust the offsets of DATASTUFF, CODESTUFF
  373.              and EVENMORESTUFF relative to their respective segment starting
  374.              addresses. I didn't say that this was good programming, I only
  375.              said that it was possible. 
  376.  
  377.              Thoroughly confused? You're not alone. Just remember, in all
  378.              compiled languages, we are going to combine these four types of
  379.              segments into a single group where offsets are relative to the
  380.              very beginning of the data. 
  381.  
  382.              Before getting you even more confused, let's take a look at what
  383.              we have so far. Make sure you actually do all of the following
  384.  
  385.  
  386.  
  387.  
  388.              The PC Assembler Tutor                                        282
  389.              ______________________
  390.  
  391.              examples. Use template.asm and at the very top, put in the
  392.              following segments:
  393.  
  394.                  ; - - - - - - - - -  
  395.                  SEG1  SEGMENT 'STUFF' 
  396.                            db  100  dup (?) 
  397.                  seg1_data db  ? 
  398.                            db  899 dup (?) 
  399.                  SEG1 ENDS 
  400.                  ; - - - - - - - - -  
  401.                  SEG3  SEGMENT 'STUFF' 
  402.                            db  300  dup (?) 
  403.                  seg3_data db  ? 
  404.                            db  699 dup (?) 
  405.                  SEG3 ENDS 
  406.                  ; - - - - - - - - -  
  407.                  SEG5  SEGMENT 'STUFF' 
  408.                            db  500  dup (?) 
  409.                  seg5_data db  ? 
  410.                            db  499 dup (?) 
  411.                  SEG5 ENDS 
  412.                  ; - - - - - - - - -  
  413.  
  414.              Call this program QGROUP1.ASM. These segments are 1000 bytes
  415.              long, and the data names are 100, 300 and 500 bytes into their
  416.              respective segments. Because these segments will be paragraph
  417.              aligned, the second and third segments will start 1008 bytes (16
  418.              X 63) after the proceeding one. You need to tell the assembler
  419.              that these are in a group and give the proper ASSUME statement.
  420.              We'll call this QGROUP:
  421.  
  422.                     QGROUP  GROUP  SEG1, SEG3, SEG5 
  423.                     ASSUME cs:CODESTUFF, ds:DATASTUFF, ds:QGROUP 
  424.  
  425.              Here's some code:
  426.  
  427.                  ; + + + + + + + + + + + + START CODE BELOW THIS LINE 
  428.                      lea     ax, seg1_data 
  429.                      call    print_unsigned 
  430.                      lea     ax, seg3_data 
  431.                      call    print_unsigned 
  432.                      lea     ax, seg5_data 
  433.                      call    print_unsigned 
  434.                  ; + + + + + + + + + + + + END CODE ABOVE THIS LINE 
  435.  
  436.              As you can see, all we are doing is putting the addresses into AX
  437.              and then printing them as unsigned numbers. Here's the output:
  438.  
  439.                  00100 
  440.                  01308 
  441.                  02516 
  442.  
  443.              Remember, each segment is starting 1008 bytes after the start of
  444.              the previous one. Here's the same program with a few extra
  445.              segments thrown in. Call it QGROUP2.ASM.:
  446.  
  447.                  ; - - - - - - - - -  
  448.  
  449.  
  450.  
  451.  
  452.              Chapter 26 - Simplifying The Template                         283
  453.              _____________________________________
  454.  
  455.                  SEG1  SEGMENT  'STUFF' 
  456.                            db  100  dup (?) 
  457.                  seg1_data db  ? 
  458.                            db  899 dup (?) 
  459.                  SEG1 ENDS 
  460.                  ; - - - - - - - - -  
  461.                  SEG2  SEGMENT  'STUFF' 
  462.                            db  200  dup (?) 
  463.                  seg2_data db  ? 
  464.                            db  799 dup (?) 
  465.                  SEG2 ENDS 
  466.                  ; - - - - - - - - -  
  467.                  SEG3  SEGMENT  'STUFF' 
  468.                            db  300  dup (?) 
  469.                  seg3_data db  ? 
  470.                            db  699 dup (?) 
  471.                  SEG3 ENDS 
  472.                  ; - - - - - - - - -  
  473.                  SEG4  SEGMENT  'STUFF' 
  474.                            db  400  dup (?) 
  475.                  seg4_data db  ? 
  476.                            db  599 dup (?) 
  477.                  SEG4 ENDS 
  478.                  ; - - - - - - - - -  
  479.                  SEG5  SEGMENT  'STUFF' 
  480.                            db  500  dup (?) 
  481.                  seg5_data db  ? 
  482.                            db  499 dup (?) 
  483.                  SEG5 ENDS 
  484.                  ; - - - - - - - - -  
  485.  
  486.              This is almost the same thing but we have added two more
  487.              segments. We are NOT going to join these two segments into the
  488.              group. Here's the GROUP and ASSUME statements:
  489.  
  490.                     QGROUP  GROUP  SEG1, SEG3, SEG5 
  491.                     ASSUME  ds:SEG2, ds:SEG4 
  492.                     ASSUME cs:CODESTUFF, ds:DATASTUFF, ds:QGROUP 
  493.  
  494.              Make sure the ASSUME statements are in that order or things may
  495.              get confused. We also add some code:
  496.  
  497.                  ; + + + + + + + + + + + + START CODE BELOW THIS LINE 
  498.                      lea     ax, seg1_data 
  499.                      call    print_unsigned 
  500.                      lea     ax, seg2_data 
  501.                      call    print_unsigned 
  502.                      lea     ax, seg3_data 
  503.                      call    print_unsigned 
  504.                      lea     ax, seg4_data 
  505.                      call    print_unsigned 
  506.                      lea     ax, seg5_data 
  507.                      call    print_unsigned 
  508.                  ; + + + + + + + + + + + + END CODE ABOVE THIS LINE 
  509.  
  510.              This shows the addresses of all five variables. Here's the new
  511.              output:
  512.  
  513.  
  514.  
  515.  
  516.              The PC Assembler Tutor                                        284
  517.              ______________________
  518.  
  519.  
  520.                  00100 
  521.                  00200 
  522.                  02316 
  523.                  00400 
  524.                  04532 
  525.  
  526.              As you can see, the GROUPed segments have their offsets relative
  527.              to the beginning of the group while the others have their offsets
  528.              relative to the beginning of the segment.
  529.  
  530.              Make a copy of QGROUP1.ASM and call it QGROUP?.ASM. Leave the
  531.              segment definitions, group definitions, ASSUME statements and
  532.              code the same, but add six more lines of code at the end:
  533.  
  534.                      ; compare the offsets 
  535.                      mov     ax, offset seg1_data 
  536.                      call    print_unsigned 
  537.                      mov     ax, offset seg3_data 
  538.                      call    print_unsigned 
  539.                      mov     ax, offset seg5_data 
  540.                      call    print_unsigned 
  541.                  ; + + + + + + + + + + + + + + + END CODE ABOVE THIS LINE 
  542.  
  543.              After the three LEAs we now do 3 OFFSETS. Assemble and link this.
  544.              Here's the output:
  545.  
  546.                  00100 
  547.                  01308 
  548.                  02516 
  549.                  00100 
  550.                  00300 
  551.                  00500 
  552.  
  553.              Wait a minute! Those last three numbers should be the same as the
  554.              first three numbers. That's right, folks. This is a known error
  555.              in the MASM assembler. In fact the Turbo Assembler copies this
  556.              mistake when it is in "MASM" mode but does it right when it is in
  557.              "IDEAL" mode. A86 does it right all the time. Here is the output
  558.              from the same source file when assembled by A86:
  559.  
  560.                  00100 
  561.                  01308 
  562.                  02516 
  563.                  00100 
  564.                  01308 
  565.                  02516 
  566.  
  567.              You have told the assembler to calculate all offsets relative to
  568.              the beginning of the group and MASM is ignoring you every time
  569.              you use the OFFSET operator. The code fix for this is to use an
  570.              override when you use OFFSET:
  571.                
  572.                       ; compare the offsets 
  573.                      mov     ax, offset QGROUP:seg1_data 
  574.                      call    print_unsigned 
  575.                      mov     ax, offset QGROUP:seg3_data 
  576.  
  577.  
  578.  
  579.  
  580.              Chapter 26 - Simplifying The Template                         285
  581.              _____________________________________
  582.  
  583.                      call    print_unsigned 
  584.                      mov     ax, offset QGROUP:seg5_data 
  585.                      call    print_unsigned 
  586.                  ; + + + + + + + + + + + + + + + END CODE ABOVE THIS LINE 
  587.  
  588.              Better yet, use LEA whenever possible. If you do use OFFSET with
  589.              groups, you need to go through the text file with a word search
  590.              to make sure that all OFFSETs have a group override. This is a
  591.              subtle error and it is very hard to find if you are not looking
  592.              for it. 
  593.  
  594.  
  595.              This system is designed so that we can have 64k of data and
  596.              stack, all of which is addressable with DS without changing DS's
  597.              value. What happens if you have more data than that? One thing
  598.              for sure is that you don't have more than 64k of individually
  599.              named variables. Either that or you have some huge calluses on
  600.              your typing fingers. 
  601.  
  602.              What you do have is arrays. If you run into space problems, you
  603.              move the least used or the biggest arrays into their own
  604.              segments. You can have one segment per array if you want. The
  605.              standardized high-level language names for these segments is:
  606.  
  607.                  ; - - - - - - - - - - - - - - - - - - - - -
  608.                  FAR_DATA  SEGMENT  PARA  'FAR_DATA'
  609.                  FAR_DATA  ENDP
  610.                  ; - - - - - - - - - - - - - - - - - - - - -
  611.                  FAR_BSS   SEGMENT  PARA  'FAR_BSS'
  612.                  FAR_BSS   ENDP
  613.                  ; - - - - - - - - - - - - - - - - - - - - -
  614.  
  615.              Once again, the '_DATA' is for initialized data while the '_BSS'
  616.              is for uninitialized data. Use only the 'FAR_DATA' kind.{2} You
  617.              will notice that these segments are NOT PUBLIC. Although an
  618.              assembler will unify all segments with the same definition that
  619.              are in the same file, the linker will not unify segments from
  620.              different files which are not PUBLIC. If we create 4 different
  621.              .ASM files, each with one segment:
  622.  
  623.                  ; FARDATA1.ASM
  624.                  PUBLIC data1
  625.                  ; - - - - - - - - - - - - - - - - - - - - -
  626.                  FAR_DATA  SEGMENT  PARA  'FAR_DATA'
  627.                  data1     db   1A67h dup (0)
  628.                  FAR_DATA  ENDS
  629.                  ; - - - - - - - - - - - - - - - - - - - - -
  630.  
  631.                  ; FARDATA2.ASM
  632.                  PUBLIC data2
  633.              ____________________
  634.  
  635.                 2. A high-level language has the right to set all the data of
  636.              a 'BSS' segment to zero as part of its startup routine. Whether
  637.              it does so or not depends on what it has told the linker. If you
  638.              put initialized data into either a '_BSS' or a 'FAR_BSS' segment,
  639.              it might easily wind up zero after startup.
  640.  
  641.  
  642.  
  643.  
  644.              The PC Assembler Tutor                                        286
  645.              ______________________
  646.  
  647.                  ; - - - - - - - - - - - - - - - - - - - - -
  648.                  FAR_DATA  SEGMENT  PARA  'FAR_DATA'
  649.                  data2     db   0D4A8h dup (0)
  650.                  FAR_DATA  ENDS
  651.                  ; - - - - - - - - - - - - - - - - - - - - -
  652.  
  653.                  FARDATA3.ASM
  654.                  PUBLIC data3
  655.                  ; - - - - - - - - - - - - - - - - - - - - -
  656.                  FAR_DATA  SEGMENT  PARA  'FAR_DATA'
  657.                  data3     db   200h dup (0)
  658.                  FAR_DATA  ENDS
  659.                  ; - - - - - - - - - - - - - - - - - - - - -
  660.  
  661.                  FARDATA4.ASM
  662.                  PUBLIC  data4
  663.                  ; - - - - - - - - - - - - - - - - - - - - -
  664.                  FAR_DATA  SEGMENT PARA  'FAR_DATA'
  665.                  data4     db   8716h dup (0)
  666.                  FAR_DATA  ENDS
  667.                  ; - - - - - - - - - - - - - - - - - - - - -
  668.  
  669.              and link these with TEMPLATE.OBJ and ASMHELP, we will get the
  670.              following .MAP file:
  671.  
  672.                   Start  Stop   Length Name                   Class 
  673.                   00000H 01A66H 01A67H FAR_DATA               FAR_DATA 
  674.                   01A70H 0EF17H 0D4A8H FAR_DATA               FAR_DATA 
  675.                   0EF20H 0F11FH 00200H FAR_DATA               FAR_DATA 
  676.                   0F120H 17835H 08716H FAR_DATA               FAR_DATA 
  677.                   17840H 1823FH 00A00H STACKSEG               STACK 
  678.                   18240H 1875DH 0051EH DATASTUFF              DATA 
  679.                   18760H 1A02FH 018D0H CODESTUFF              CODE 
  680.               
  681.                  Program entry point at 1876:0000 
  682.  
  683.              The numbers in the segment definitions were in hex so you could
  684.              read the .MAP file more easily. We have created four different
  685.              FAR_DATAs - one for each variable. 
  686.  
  687.              The idea here is to leave DS alone if possible and use ES:SI or
  688.              ES:DI for your manipulation of the array.
  689.  
  690.                  mov  ax, seg data1
  691.                  mov  es, ax
  692.                  mov  si, offset data1
  693.  
  694.              Of course, if you using two different FAR_DATA arrays from two
  695.              different segments at the same time, you will probably need to
  696.              use DS temporarily. This is the kind of thing you need to plan
  697.              before you start a program which contains large arrays.
  698.  
  699.  
  700.  
  701.  
  702.  
  703.  
  704.  
  705.  
  706.  
  707.  
  708.              Chapter 26 - Simplifying The Template                         287
  709.              _____________________________________
  710.  
  711.              You have now seen all possible segments for any Microsoft
  712.              language and for Turbo C.{3} These are: 
  713.  
  714.  
  715.                  _DATA  SEGMENT WORD PUBLIC 'DATA'
  716.                  CONST  SEGMENT WORD PUBLIC 'CONST'
  717.                  _BSS   SEGMENT WORD PUBLIC 'BSS'
  718.                  STACK  SEGMENT PARA STACK 'STACK'
  719.                  _TEXT  SEGMENT WORD PUBLIC 'CODE'
  720.  
  721.                  name_TEXT SEGMENT WORD PUBLIC 'CODE'
  722.                  FAR_DATA  SEGMENT PARA  'FAR_DATA'
  723.                  FAR_BSS   SEGMENT PARA  'FAR_BSS'
  724.  
  725.                  DGROUP  GROUP  _DATA, CONST, _BSS, STACK
  726.  
  727.  
  728.              We have another problem on our road to simplification. We want DS
  729.              to have the address of the start of DGROUP. How do we do it?
  730.              Well, before we had:
  731.  
  732.                  mov  ax, DATASTUFF
  733.                  mov  ds, ax
  734.  
  735.              DATASTUFF was a segment. We do the same thing for groups:
  736.  
  737.                  mov  ax, DGROUP
  738.                  mov  ds, ax
  739.  
  740.              We use a group name instead of a segment name. This means that
  741.              our ultimate code segment will look like this
  742.  
  743.                  ; - - - - - - - - - - 
  744.                  _TEXT  SEGMENT WORD PUBLIC 'CODE'
  745.  
  746.                       DGROUP  GROUP  _DATA, CONST, _BSS, STACK
  747.                       ASSUME cs:_TEXT, ds:DGROUP
  748.  
  749.                  start:
  750.                       mov  ax, DGROUP
  751.                       mov  ds, ax
  752.  
  753.                       ; - - - - - - - - - -
  754.                       ; the program goes here
  755.                       ; - - - - - - - - - -
  756.  
  757.                       mov  ah, 4Ch
  758.              ____________________
  759.  
  760.                 3. If you are using Turbo PASCAL, then there are only two
  761.              segments possible. They are:
  762.  
  763.                  DATA  SEGMENT WORD PUBLIC 
  764.                  CODE  SEGMENT BYTE PUBLIC
  765.  
  766.              There is no class name. You can substitute DSEG for DATA and CSEG
  767.              for CODE if you want. Turbo Pascal has no DGROUP.
  768.  
  769.  
  770.  
  771.  
  772.              The PC Assembler Tutor                                        288
  773.              ______________________
  774.  
  775.                       mov  al, ?          ; replace ? with error code
  776.                       int  21h
  777.  
  778.                  _TEXT  ENDS
  779.                  ; - - - - - - - - - -
  780.  
  781.              Say, if all this stuff is standardized text, why are we forced to
  782.              type all this drivel over and over again. The answer is that we
  783.              aren't. All the segment information has a shorthand. Here's how
  784.              it works. Every shorthand symbol starts with a dot. The assembler
  785.              will then generate the desired text.{4} This is from MASM 5.0 on,
  786.              so if you have an earlier assembler you'll have to write the full
  787.              text.
  788.  
  789.              To start out, use the two starting directives DOSSEG (with no
  790.              dot) and .MODEL. MODEL will be explained later.{5}
  791.  
  792.                       DOSSEG
  793.                       .MODEL Medium
  794.  
  795.              For now, 'medium' is what we want.
  796.  
  797.              From that point, if you want a data segment, you just write
  798.              .DATA, if you want code, you write .CODE. Every time that the
  799.              assembler sees a segment directive it will close any segment that
  800.              is open and start the segment indicated by the directive. (You
  801.              can always reopen a segment). Here is what replaces the
  802.              directives:
  803.  
  804.                  DIRECTIVE                REPLACEMENT TEXT
  805.  
  806.                  .DATA               _DATA  SEGMENT WORD PUBLIC 'DATA'
  807.                  .CONST              CONST  SEGMENT WORD PUBLIC 'CONST'
  808.                  .DATA?              _BSS   SEGMENT WORD PUBLIC 'BSS'
  809.                  .STACK [size]       STACK  SEGMENT PARA STACK 'STACK'
  810.                  .CODE               _TEXT  SEGMENT WORD PUBLIC 'CODE'
  811.  
  812.                  .CODE [name]        name_TEXT SEGMENT WORD PUBLIC 'CODE'
  813.                  .FARDATA [name]     FAR_DATA  SEGMENT PARA  'FAR_DATA'
  814.                  .FARDATA? [name]    FAR_BSS   SEGMENT PARA  'FAR_BSS'
  815.  
  816.              The [name] in brackets will be explained in a minute. The [size]
  817.              after the stack declaration allows you to customize the size of
  818.              the stack. Without any size, the declaration
  819.  
  820.                  .STACK
  821.  
  822.              will allocate 1k of memory for the stack. A size allocates a
  823.              ____________________
  824.  
  825.                 4. It really generates no text. It is just that the assembler
  826.              will generate the same machine code as if that text had been
  827.              generated.
  828.  
  829.                 5. DOSSEG tells the assembler to tell the linker that the .EXE
  830.              file should have the standard segment  order. It is not necessary
  831.              but it doesn't hurt.
  832.  
  833.  
  834.  
  835.  
  836.              Chapter 26 - Simplifying The Template                         289
  837.              _____________________________________
  838.  
  839.              specific number of bytes:
  840.  
  841.                  .STACK 2000h
  842.  
  843.              You can make it anything you want, but make sure it is an even
  844.              number and remember that the limit for all four parts of DGROUP
  845.              is 64k.
  846.  
  847.              To see how the names work, we need some text files. Here is a
  848.              complete main file:
  849.  
  850.                  ; FARDATA.ASM   - driver module 
  851.                  DOSSEG 
  852.                  .MODEL  medium
  853.                  EXTRN  data2_routine:FAR, data3_routine:FAR
  854.                  .STACK  200h 
  855.                  .FARDATA
  856.                       data1     db   0100h dup (0) 
  857.                  .CODE 
  858.                  main: 
  859.                       mov  ax, DGROUP 
  860.                       mov  ds, ax 
  861.                       call data2_routine 
  862.                       call data3_routine 
  863.                       mov  ax, 4C00h 
  864.                       int 21h 
  865.                  END  main 
  866.  
  867.              It has some data and some code though it doesn't really do
  868.              anything. We will use this along with two other files for the
  869.              examples. Here is FARDATA2:
  870.  
  871.                  ; FARDATA2.ASM 
  872.                  DOSSEG 
  873.                  .MODEL  medium
  874.                  PUBLIC data2_routine 
  875.                  .FARDATA 
  876.                       data2     db   0200h dup (0) 
  877.                  .CODE 
  878.                  data2_routine  proc 
  879.                       ret 
  880.                  data2_routine endp 
  881.                  END 
  882.  
  883.              Notice that data2_routine doesn't have a FAR or NEAR. That's
  884.              being taken care of by the memory model. Data2_routine's type
  885.              does need to be declared EXTRN in the main module. The third
  886.              routine has similar code. Here is the .MAP file when they are
  887.              combined:
  888.  
  889.               
  890.                   Start  Stop   Length Name                   Class 
  891.                   00000H 00013H 00014H FARDATA_TEXT           CODE 
  892.                   00014H 00014H 00001H FARDATA2_TEXT          CODE 
  893.                   00016H 00016H 00001H FARDATA3_TEXT          CODE 
  894.                   00020H 0011FH 00100H FAR_DATA               FAR_DATA 
  895.                   00120H 0031FH 00200H FAR_DATA               FAR_DATA 
  896.  
  897.  
  898.  
  899.  
  900.              The PC Assembler Tutor                                        290
  901.              ______________________
  902.  
  903.                   00320H 0061FH 00300H FAR_DATA               FAR_DATA 
  904.                   00620H 00620H 00000H _DATA                  DATA 
  905.                   00620H 0081FH 00200H STACK                  STACK 
  906.  
  907.  
  908.              You can see the FAR_DATAs there, but where did the FARDATA3_TXT
  909.              come from? The assembler decided that we wanted independent code
  910.              segments and gave each one the name of the assembler file it came
  911.              from. Since all the object files in a program must have unique
  912.              names, these segment names should also be unique. If we change
  913.              the .MODEL from MEDIUM to COMPACT without touching anything else,
  914.              then we get:
  915.  
  916.               
  917.                   Start  Stop   Length Name                   Class 
  918.                   00000H 00022H 00023H _TEXT                  CODE 
  919.                   00030H 0012FH 00100H FAR_DATA               FAR_DATA 
  920.                   00130H 0032FH 00200H FAR_DATA               FAR_DATA 
  921.                   00330H 0062FH 00300H FAR_DATA               FAR_DATA 
  922.                   00630H 00630H 00000H _DATA                  DATA 
  923.                   00630H 0082FH 00200H STACK                  STACK 
  924.  
  925.              If we now put a name after the .FARDATA directive, it will give
  926.              the segment a unique name. Putting:
  927.  
  928.                  .FARDATA  jake_the_snake 
  929.  
  930.              in  FARDATA2.ASM, along with name changes in the other modules
  931.              results in the following .MAP file:
  932.               
  933.  
  934.                   Start  Stop   Length Name                   Class 
  935.                   00000H 00022H 00023H _TEXT                  CODE 
  936.                   00030H 0012FH 00100H HACKSAW                FAR_DATA 
  937.                   00130H 0032FH 00200H JAKE_THE_SNAKE         FAR_DATA 
  938.                   00330H 0062FH 00300H HULKSTER               FAR_DATA 
  939.                   00630H 00630H 00000H _DATA                  DATA 
  940.                   00630H 0082FH 00200H STACK                  STACK 
  941.  
  942.  
  943.  
  944.              We are doing a number of interrelated things here, so let's try
  945.              to unify what is going on. You have seen both NEAR and FAR
  946.              routines in the Tutor. A NEAR routine alters IP and restores IP
  947.              on the return. A FAR routine alters both CS and IP and restores
  948.              them on the return. 
  949.  
  950.              When we passed addresses of data, we have almost always passed
  951.              just the offset of the data. That is because the data has almost
  952.              always been in the DATASTUFF SEGMENT, and the value of DS has
  953.              been known. In Chapter 19 we did "move_pascal_string" which was a
  954.              subroutine where we passed both the segment and offset of the
  955.              data. These are our two choices for passing addresses:
  956.  
  957.                       OFFSET           1 word
  958.                       SEGMENT:OFFSET   2 words
  959.  
  960.  
  961.  
  962.  
  963.  
  964.              Chapter 26 - Simplifying The Template                         291
  965.              _____________________________________
  966.  
  967.              This gives us four basic possiblilities for program structure:
  968.  
  969.                  SUBROUTINE CALL     DATA ADDRESSES PASSED AS
  970.  
  971.                       NEAR               OFFSET
  972.                       FAR                OFFSET
  973.                       NEAR               SEGMENT:OFFSET
  974.                       FAR                SEGMENT:OFFSET
  975.  
  976.              Each of these structural possibilities has a name called a MODEL
  977.              name. They are:
  978.  
  979.                  SUBROUTINE CALL      ADDRESSES PASSED AS        MODEL NAME
  980.  
  981.                       NEAR               OFFSET                   SMALL
  982.                       FAR                OFFSET                   MEDIUM
  983.                       NEAR               SEGMENT:OFFSET           COMPACT
  984.                       FAR                SEGMENT:OFFSET           LARGE
  985.  
  986.  
  987.              You tell the assembler which model you are working with by using
  988.              the .MODEL directive:
  989.  
  990.                  .MODEL  medium
  991.  
  992.              The assembler will then make either NEAR or FAR the default type.
  993.              This can be overridden if you have explicitly given a NEAR or
  994.              FAR:
  995.  
  996.                  my_proc  procedure
  997.  
  998.              will generate the correct subroutine calls and returns for that
  999.              model, while:
  1000.  
  1001.                  my_proc1  procedure  near
  1002.                  my_proc2  procedure  far
  1003.  
  1004.              will remain unaltered.
  1005.  
  1006.              At the assembler level, you need to code the address passing
  1007.              yourself, but if you have a MODEL and you are connected to a
  1008.              high-level language (with the same .MODEL type), the high-level
  1009.              language will pass all addresses as stated above.
  1010.  
  1011.              The advantage of this system is that using the .MODEL directive
  1012.              and appropriate EQU statements and MACROS (which we have not
  1013.              covered), it is possible to write a single subroutine which can
  1014.              then be assembled in all four model configurations. Coding this
  1015.              is non-trivial, but when you have done more programming you will
  1016.              see how to deal with the stack using EQUs and MACROs.
  1017.  
  1018.              For now, you want to stay with data addresses which are passed by
  1019.              offset only. This is much easier. These are the SMALL and MEDIUM
  1020.              models. Whether you choose NEAR or FAR procedures doesn't affect
  1021.              much except where parameters are on the stack (because of that
  1022.              extra CS).
  1023.  
  1024.  
  1025.  
  1026.  
  1027.  
  1028.              The PC Assembler Tutor                                        292
  1029.              ______________________
  1030.  
  1031.              Are these .MODELS important? They are nice, but not particularly
  1032.              vital. What happens is that in a manual you see a sample program
  1033.              like this:
  1034.  
  1035.                  DOSSEG
  1036.                  .MODEL medium
  1037.                  .STACK
  1038.                  .DATA
  1039.                  variable1 dw 25
  1040.                  .CODE
  1041.                  sample proc
  1042.                  mov  ax, variable1
  1043.                  ret
  1044.                   sample  endp   
  1045.                  ENDS
  1046.                  END
  1047.  
  1048.              and you start comparing the size of this to the size it would be
  1049.              if you used the standard segment definitions. I have news for
  1050.              you. This is not a legitimate program. A legitimate program is a
  1051.              page or two long.{6} Also, at least to my way of thinking, you
  1052.              want visual separation between segments. The above is a
  1053.              disordered presentation of segments. We want order in our
  1054.              programs and the segment headers provide a visual structure. In
  1055.              the text file for ASMHELP, (which is about 3600 lines long), the
  1056.              SEGMENT declarations occupy about 20 lines. This is about 0.5% of
  1057.              the total length of the file.
  1058.  
  1059.              If you are going to assemble a file in multiple models, then it
  1060.              is worthwhile to use the .MODEL directives, otherwise it is
  1061.              optional depending more on your concept of what looks clear than
  1062.              any major difference.
  1063.  
  1064.  
  1065.  
  1066.  
  1067.  
  1068.  
  1069.  
  1070.  
  1071.  
  1072.  
  1073.  
  1074.  
  1075.  
  1076.  
  1077.  
  1078.  
  1079.  
  1080.  
  1081.  
  1082.  
  1083.  
  1084.              ____________________
  1085.  
  1086.                 6. Perhaps you want to scan \COMMENTS\MISHMASH.DOC which
  1087.              contains some real subroutines. They are all long.
  1088.  
  1089.  
  1090.  
  1091.  
  1092.              Chapter 26 - Simplifying The Template                         293
  1093.              _____________________________________
  1094.  
  1095.                                       SUMMARY
  1096.  
  1097.              To exit a program, use INT 21h Function 4Ch
  1098.  
  1099.                  mov   ah, 4Ch         ; exit program
  1100.                  mov   al, ?           ; replace ? with error code
  1101.                  int   21h
  1102.  
  1103.  
  1104.              A GROUP is a group of segments whose data will be referenced by
  1105.              the offset from the beginning of the group. You declare a group
  1106.              with:
  1107.  
  1108.                  DGROUP  GROUP  _DATA, CONST, _BSS, STACK
  1109.  
  1110.              MASM calculates OFFSETS incorectly with groups, so you should
  1111.              either use LEA or the DGROUP override:
  1112.  
  1113.                  lea  ax, variable1
  1114.                  mov  ax, offset DGROUP:variable1
  1115.  
  1116.              To get the address of DGROUP in DS you need:
  1117.  
  1118.                  ASSUME ds:DGROUP
  1119.  
  1120.              and:
  1121.  
  1122.                  mov  ax, DGROUP
  1123.                  mov  ds, ax
  1124.  
  1125.  
  1126.  
  1127.              The standardized segment definitions, along with their simplified
  1128.              directives are:
  1129.  
  1130.                  DIRECTIVE                REPLACEMENT TEXT
  1131.  
  1132.                  .DATA               _DATA  SEGMENT WORD PUBLIC 'DATA'
  1133.                  .CONST              CONST  SEGMENT WORD PUBLIC 'CONST'
  1134.                  .DATA?              _BSS   SEGMENT WORD PUBLIC 'BSS'
  1135.                  .STACK [size]       STACK  SEGMENT PARA STACK 'STACK'
  1136.                  .CODE               _TEXT  SEGMENT WORD PUBLIC 'CODE'
  1137.  
  1138.                  .CODE [name]        name_TEXT SEGMENT WORD PUBLIC 'CODE'
  1139.                  .FARDATA [name]     FAR_DATA  SEGMENT PARA  'FAR_DATA'
  1140.                  .FARDATA? [name]    FAR_BSS   SEGMENT PARA  'FAR_BSS'
  1141.  
  1142.  
  1143.              In addition you have the different model names:
  1144.  
  1145.                  SUBROUTINE CALL      ADDRESSES PASSED AS        .MODEL NAME
  1146.  
  1147.                       NEAR               OFFSET                   SMALL
  1148.                       FAR                OFFSET                   MEDIUM
  1149.                       NEAR               SEGMENT:OFFSET           COMPACT
  1150.                       FAR                SEGMENT:OFFSET           LARGE
  1151.  
  1152.